Skip to content

feat(decisioning): state-machine helpers, typed exceptions, ref_account_id#467

Closed
bokelley wants to merge 2 commits intomainfrom
claude/issue-455-decisioning-helpers
Closed

feat(decisioning): state-machine helpers, typed exceptions, ref_account_id#467
bokelley wants to merge 2 commits intomainfrom
claude/issue-455-decisioning-helpers

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 3, 2026

Closes #455

Adds three sets of additive helpers to adcp.decisioning (Batch 1 item 3 of the JS 6.7 parity epic #452). All additions are non-breaking new exports; no public symbols changed or removed.

(a) State-machine transition helpers (src/adcp/decisioning/transitions.py) — MEDIA_BUY_TRANSITIONS and CREATIVE_TRANSITIONS are dict[Status, set[Status]] maps derived from the spec state-machine diagrams. validate_media_buy_transition / validate_creative_transition accept raw strings or enum members and raise AdcpError(INVALID_REQUEST, recovery="correctable") on disallowed moves or unknown status strings — eliminating the bare ValueError leak that open-coded enum lookups produce. Creative rejected→processing (resubmit) and archived→approved (unarchive) paths are included per creative-status.json enumDescriptions.

(b) Typed AdcpError subclasses (src/adcp/decisioning/exceptions.py) — PermissionDeniedError, AuthRequiredError, ServiceUnavailableError, RateLimitedError, MediaBuyNotFoundError, AccountNotFoundError, BillingNotPermittedForAgentError, RequestValidationError. Each hard-codes the correct wire code and recovery value from enumMetadata in schemas/cache/enums/error-code.json (the spec's authoritative SDK classification block). Named RequestValidationError (not ValidationError) to avoid shadowing pydantic.ValidationError and the existing adcp.validation.legacy.ValidationError.

(c) ref_account_id(ref) -> str | None — extracts account_id from a wire account reference dict, returning None for missing/non-string values. Eliminates ref.get("account_id") if ref else None inline patterns in multi-tenant platform methods.

What was tested

  • pytest tests/test_decisioning_transitions_exceptions.py — 56 new tests, all passing
  • pytest tests/test_decisioning_types.py tests/test_decisioning_dispatch.py — 57 existing tests, all passing, no regressions
  • ruff check — clean on all new files
  • mypy src/adcp/decisioning/exceptions.py src/adcp/decisioning/types.py — no issues
  • mypy src/adcp/decisioning/transitions.py src/adcp/decisioning/types.py — no issues

Pre-PR review

  • code-reviewer: approved after one fix iteration — caught that PERMISSION_DENIED and BILLING_NOT_PERMITTED_FOR_AGENT are correctable per spec enumMetadata (not terminal); both corrected before PR open.
  • dx-expert: approved — nits only: (1) quickstart docstring in __init__.py doesn't mention the new helpers (omitted per nit policy); (2) ref_account_id placement in transitions.py rather than a dedicated helpers.py (placement is acceptable given the module docstring already covers "account-reference utilities"; follow-up issue if it creates agent-tax); (3) validate_* functions raise AdcpError(INVALID_REQUEST) not RequestValidationError — correct and intentional, but worth a doc note on the validate functions.

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout <num>
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See adcp#3121
for context.

Session: https://claude.ai/code/session_01XbBfrSnfmVy6fQtoebgxWJ


Generated by Claude Code

claude added 2 commits May 3, 2026 11:44
…nt_id (#455)

Adds three sets of additive helpers to adcp.decisioning (issue #455, Batch 1 item 3
of the JS 6.7 parity epic #452):

(a) State-machine transition helpers
- MEDIA_BUY_TRANSITIONS: dict[MediaBuyStatus, set[MediaBuyStatus]] — valid
  from→{to} moves per spec; terminals map to empty set
- validate_media_buy_transition(from, to): raises AdcpError(INVALID_REQUEST)
  on disallowed transitions or unknown status strings
- CREATIVE_TRANSITIONS / validate_creative_transition — same shape; includes
  the rejected→processing resubmit path and archived→approved unarchive path
  from creative-status.json (would have been missing in the original proposal)

(b) Typed AdcpError subclasses in adcp.decisioning.exceptions
PermissionDeniedError, AuthRequiredError, ServiceUnavailableError,
RateLimitedError, MediaBuyNotFoundError, AccountNotFoundError,
BillingNotPermittedForAgentError, RequestValidationError — each hard-codes
the correct wire code and recovery semantics so adopters don't open-code
AdcpError(code=..., recovery=...) inline. Named RequestValidationError (not
ValidationError) to avoid shadowing pydantic.ValidationError.

(c) ref_account_id(ref) -> str | None
Extracts account_id from a wire account reference dict; eliminates the
ref.get('account_id') if ref else None inline pattern.

56 new tests, all passing. Ruff and mypy clean on new files.

https://claude.ai/code/session_01XbBfrSnfmVy6fQtoebgxWJ
…NOT_PERMITTED_FOR_AGENT

Both codes classify as 'correctable' in the spec's enumMetadata block
(schemas/cache/enums/error-code.json), not 'terminal'. The initial
implementation used the wrong recovery value; this aligns with the
authoritative enumMetadata classification that SDKs MUST consume.

https://claude.ai/code/session_01XbBfrSnfmVy6fQtoebgxWJ
@bokelley
Copy link
Copy Markdown
Contributor Author

bokelley commented May 4, 2026

Superseded by #465 (feat(decisioning): state-machine helpers + typed exception classes + ref_account_id), already merged to main. Same three-part scope: transitions, typed exceptions, ref_account_id.

@bokelley bokelley closed this May 4, 2026
@bokelley bokelley deleted the claude/issue-455-decisioning-helpers branch May 4, 2026 08:51
@bokelley
Copy link
Copy Markdown
Contributor Author

bokelley commented May 4, 2026

Acknowledged — noted that this was superseded by #465 (already merged to main). No further action needed on this PR.


Generated by Claude Code


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(decisioning): state-machine helpers + typed exception classes + refAccountId

2 participants